/* Definition of default mask writing modes.
 *
 * Copyright (c) 1993-2007 Leo Spiekman, Xaveer Leijtens
 *
 * This file is part of libMask.
 *
 * libMask is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * libMask is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with libMask.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mask.h"

/*
 * The declaration of the default values can be overridden by putting a
 * line "unsigned int mode = <value>;" before definition of main_layout().
 * See mask.h for the meaning of the values.
 */
unsigned int mode = FILLED | POLYGON | GRIDDED;

#define MSK_GDSII_NAMELENGTH 32

struct layout layouts[MSK_MAX_LAYOUTS];
int num_layout = 0;

void msk_sublayout(int n)
{
  if (mode&FLATTENED) {
    /* Flat: write to the mask file for each instance */
    push_cp();
      layouts[n].func(n);
    pop_cp();
  } else {
    /* Not flat: reference the sublayout */
    msklayout(n, layouts[n].name, cp.a, cp.x, cp.y, cp.flip);
  } 
}

int msk_add_sublayout(const char* name, void (*func)(int))
{ 
  int i;
  if (num_layout >= MSK_MAX_LAYOUTS - 1) {
    fprintf(stderr, "ERROR: msk_add_sublayout: maximum number of sublayouts reached (%d)\n  Aborting... mask layout will be invalid.\n", MSK_MAX_LAYOUTS);
    exit(1);
  }
  /* Check for duplicate names */
  for (i=0; i<num_layout; i++) {
    if (!strncmp(name, layouts[i].name, MSK_GDSII_NAMELENGTH)) {
      fprintf(stderr, "ERROR: msk_add_sublayout: sublayout names must be unique.\n  First %d characters of\n  %s and\n  %s are identical\n Aborting... mask layout will be invalid.\n", MSK_GDSII_NAMELENGTH, name, layouts[i].name);
    exit(1);
    }
  }
#ifdef __MINGW32__
  layouts[num_layout].name = strdup(name);//to avoid strndup
  //fprintf(stderr, "%s -> %s", name, layouts[num_layout].name);
#else
  layouts[num_layout].name = strndup(name, MSK_GDSII_NAMELENGTH);
  //fprintf(stderr, "%s -> %s", name, layouts[num_layout].name);  
#endif
  layouts[num_layout++].func = func;
 //fprintf(stdout, "msk_add_sublayout: called function: %p\n", func);//DEBUG
  return(num_layout - 1);
}

int msk_init(const char *top_cell)
{
  MASK = stdout;
  init_pstack();
  msk_add_sublayout(top_cell, NULL); /* the main layout */
  /* last added has always the number num_layout-1 */

  return(0);
}

/* standard function for file inclusion */
void sublayout_file(int n)
{
  FILE *fp;
  char *buffer;
  char fln[1024];
  unsigned long fileLen;

  sprintf(fln, "%s%03d", TMP_NAME_TMPL, n);
  if ((fp = fopen(fln, "r")) == NULL) {
    fprintf(stderr, "Can't open file '%s' for reading.\n", fln);
    exit(1);
  }
  //Get file length
  fseek(fp, 0, SEEK_END);
  fileLen = ftell(fp);
  fseek(fp, 0, SEEK_SET);

  //Allocate memory
  buffer = (char *)malloc(fileLen + 1);
  if (!buffer) {
    fprintf(stderr, "Can't allocate memory for reading CIF file\n %s\n",
      fln);
    fclose(fp);
    exit(1);
  }
  //Read file contents into buffer
  fread(buffer, fileLen, 1, fp);
  fclose(fp);
  fwrite(buffer, fileLen, 1, MASK);
  free(buffer);
}


int msk_header(const char *filename, const char *top_cell)
{
  int l;

  msk_init(top_cell);
  /* Write mask header */
  msk_main_header(filename);
  /* Loop over the sublayouts defined */
  for (l = 0; l < num_layout-1; l++) { 
    if (! (mode&FLATTENED)) {
      /* Not flattened: write the sublayout header, code and footer. */
      this_layout = l;
      msk_sublayout_header(layouts[l].name);
      
     // fprintf(stdout, "msk_header: %s, %d \n",layouts[l].name, l); //DEBUG
     // fprintf(stdout, "msk_header: called function: %p\n", layouts[l].func);//DEBUG
      
      layouts[l].func(l);
      msk_sublayout_trailer();
    }
  }
  this_layout = l; /* main layout */
  msk_sublayout_header(top_cell);
  return(0);
}
